#include <reg52.h>
#include <absacc.h>
#include "intrins.h"
#include "sst29sf040_driver.h"

/*************************************************************************/
/* PROCEDURE:   Erase_Entire_Chip                                       */
/*                                                                      */
/* This procedure can be used to erase the entire chip.                 */
/*                                                                      */
/* Input:                                                               */
/*      Chip_numb                                                       */
/*                                                                      */
/* Output:                                                              */
/*      NONE                                                            */
/************************************************************************/

void Erase_Entire_Chip(BYTE Chip_numb){
	BYTE flash_offset[] = {0x70,0x68,0x58,0x38};/*Four chips*/
	PB_8255 = FLASH_CS & flash_offset[Chip_numb];
	UP_DOWN = 1;                                /*Set P1.3 to operate flash*/
	XBYTE[0x0555] = 0xAA;
	XBYTE[0x02AA] = 0x55;
	XBYTE[0x0555] = 0x80;
	XBYTE[0x0555] = 0xAA;
	XBYTE[0x02AA] = 0x55;
	XBYTE[0x0555] = 0x10;
	Flash_Delay_EraseChip();
	UP_DOWN = 0;                                 /*Clear P1.3 to operate ram or 8255*/
}

/************************************************************************/
/* PROCEDURE:   Erase_One_Sector                                        */
/*                                                                      */
/* This procedure can be used to erase a total of 128 bytes.            */
/*                                                                      */
/* Input:                                                               */
/*      Dst_High 8-bit high address                                     */
/*      Dst_Low  16-bit low address at which the erase operation will   */
/*               start.                                                 */
/*                                                                      */
/* Output:                                                              */
/*      NONE                                                            */
/************************************************************************/

void Erase_One_Sector(BYTE Dst_High, UINT Dst_Low){
	PB_8255 = Dst_High;
	UP_DOWN = 1;
	XBYTE[0x0555] = 0xAA;
	XBYTE[0x02AA] = 0x55;
	XBYTE[0x0555] = 0x80;
	XBYTE[0x0555] = 0xAA;
	XBYTE[0x02AA] = 0x55;
	Dst_Low = Dst_Low & 0xFF80;
	XBYTE[Dst_Low] = 0x20;
	Flash_Delay_EraseSector();
	UP_DOWN = 0;
}

/************************************************************************/
/* PROCEDURE:   Erase_Sector_ByNumb                                     */
/*                                                                      */
/* This procedure can be used to erase a total of 128 bytes.            */
/*                                                                      */
/* Input:                                                               */
/*       Sector_Numb    The number of the sector which will be erased   */
/*                                                                      */
/* Output:                                                              */
/*      NONE                                                            */
/************************************************************************/

void Erase_Sector_ByNumb(UINT Sector_Numb){
     BYTE Dst_High = (Sector_Numb >> 9) | 0x38 & 0x3F;
     UINT Dst_Low = (Sector_Numb & 0x01FF) << 7;
     PB_8255 = Dst_High;
     UP_DOWN = 1;
     XBYTE[0x0555] = 0xAA;
     XBYTE[0x02AA] = 0x55;
     XBYTE[0x0555] = 0x80;
     XBYTE[0x0555] = 0xAA;
     XBYTE[0x02AA] = 0x55;
     XBYTE[Dst_Low] = 0x20;
     Flash_Delay_EraseSector();
     UP_DOWN = 0;
}


/************************************************************************/
/* PROCEDURE:   Flash_Write(Byte_Program)                               */
/*                                                                      */
/* This procedure can be used to write one byte to the flash once       */
/*                                                                      */
/* Input:                                                               */
/*      mData    this byte will be written in the flash                  */
/*      Dst_High 8-bit high address                                     */
/*      Dst_Low  16-bit low address at which the write operation will   */
/*               start.							*/
/*                                                                      */
/* Output:                                                              */
/*      NONE                                                            */
/************************************************************************/

void Flash_Write(BYTE mData, BYTE Dst_High, UINT Dst_Low){
	PB_8255 = Dst_High;
	UP_DOWN = 1;
	XBYTE[0x0555] = 0xAA;
	XBYTE[0x02AA] = 0x55;
	XBYTE[0x0555] = 0xA0;
	XBYTE[Dst_Low] = mData;
	Flash_Delay_ByteProgram();
	UP_DOWN = 0;
}

/************************************************************************/
/* PROCEDURE:   Flash_Read(Byte_Read)                                   */
/*                                                                      */
/* This procedure can be used to read one byte from the flash once      */
/*                                                                      */
/* Input:                                                               */
/*      Dst_High 8-bit high address                                     */
/*      Dst_Low  16-bit low address at which the erase operation will   */
/*               start.							*/
/*                                                                      */
/* Output:                                                              */
/*      Data    The data read from the destination address              */
/************************************************************************/

BYTE Flash_Read(BYTE Dst_High, UINT Dst_Low){
	BYTE mData;
	PB_8255 = Dst_High;
	UP_DOWN = 1;
	mData = XBYTE[Dst_Low];
	UP_DOWN = 0;
	return mData;
}

/************************************************************************/
/* PROCEDURE:   Flash_Write_Byte                                        */
/*                                                                      */
/* This procedure can be used to write one byte to the flash once       */
/*                                                                      */
/* Input:                                                               */
/*      Data    this byte will be written in the flash                  */
/*      Sector_Numb  the number of one sector in flash                  */
/*      offset       used to determine the memory address written in    */
/*                                                                      */
/* Output:                                                              */
/*      NONE                                                            */
/************************************************************************/

void Flash_Write_Byte(UINT mData, UINT Sector_Numb, BYTE offset){
	BYTE Dst_High = (Sector_Numb >> 9) | 0x38 & 0x3F;
	UINT Dst_Low = ((Sector_Numb & 0x01FF) << 7) + offset;
	PB_8255 = Dst_High;
	UP_DOWN = 1;
	XBYTE[0x0555] = 0xAA;
	XBYTE[0x02AA] = 0x55;
	XBYTE[0x0555] = 0xA0;
	XBYTE[Dst_Low] = mData;
	Flash_Delay_ByteProgram();
	UP_DOWN = 0;
}

/************************************************************************/
/* PROCEDURE:   Flash_Read_Byte                                         */
/*                                                                      */
/* This procedure can be used to read one byte from the flash once      */
/*                                                                      */
/* Input:                                                               */
/*      Sector_Numb  the number of one sector in flash                  */
/*      offset       used to determine the memory address read from     */
/*                                                                      */
/* Output:                                                              */
/*      Data    The data read from the destination address              */
/************************************************************************/

BYTE Flash_Read_Byte(UINT Sector_Numb, BYTE offset){
	BYTE mData;
	BYTE Dst_High = ((Sector_Numb >> 9) & 0x07) | 0x38;
	UINT Dst_Low = ((Sector_Numb & 0x01FF) << 7) + offset;
	PB_8255 = Dst_High;
	UP_DOWN = 1;
	mData = XBYTE[Dst_Low];
	UP_DOWN = 0;
	return mData;
}

/************************************************************************/
/* PROCEDURE:   Flash_Write_Bytes                                       */
/*                                                                      */
/* This procedure can be used to write several bytes to the flash once  */
/*                                                                      */
/* Input:                                                               */
/*      Data_Addr this address is the begining of the data bytes        */
/*      n         the number of the bytes will be written into flash    */
/*      Sector_Numb  the number of one sector in flash                  */
/*      offset       used to determine the memory address to be written */
/*                                                                      */
/* Output:                                                              */
/*      NONE                                                            */
/************************************************************************/

void Flash_Write_Bytes(BYTE* Data_Addr, BYTE n, UINT Sector_Numb, BYTE offset){
	BYTE i;
        BYTE Dst_High = ((Sector_Numb >> 9) & 0x07) | 0x38;
        UINT Dst_Low = ((Sector_Numb & 0x01FF) << 7) + offset;

	for(i = 0; i < n; i++){
		if(offset < 127){
			PB_8255 = Dst_High;
			UP_DOWN = 1;
			XBYTE[0x0555] = 0xAA;
			XBYTE[0x02AA] = 0x55;
			XBYTE[0x0555] = 0xA0;
			XBYTE[Dst_Low] = * Data_Addr;
			Flash_Delay_ByteProgram();
			UP_DOWN = 0;
                        Dst_Low++;
                        Data_Addr++;
                        offset++;
		}else{
			PB_8255 = Dst_High;
			UP_DOWN = 1;
			XBYTE[0x0555] = 0xAA;
			XBYTE[0x02AA] = 0x55;
			XBYTE[0x0555] = 0xA0;
			XBYTE[Dst_Low] = * Data_Addr;
			Flash_Delay_ByteProgram();
			UP_DOWN = 0;
                        Data_Addr++;
			offset = 0;			   //Address step over the boundary of one sector to the next sector
			Sector_Numb = Sector_Numb + 1;
                        Dst_High = ((Sector_Numb >> 9) & 0x07) | 0x38;
                        Dst_Low = ((Sector_Numb & 0x01FF) << 7);
		}
	}


}


/************************************************************************/
/* PROCEDURE:   Flash_Read_Bytes                                        */
/*                                                                      */
/* This procedure can be used to write several bytes to the flash once  */
/*                                                                      */
/* Input:                                                               */
/*      Data_Addr this address is the begining of the data bytes        */
/*      n         the number of the bytes will be written into flash    */
/*      Sector_Numb  the number of one sector in flash                  */
/*      offset       used to determine the memory address to be written */
/*                                                                      */
/* Output:                                                              */
/*      NONE                                                            */
/************************************************************************/

void Flash_Read_Bytes(BYTE* Data_Addr, BYTE n, UINT Sector_Numb, BYTE offset){
	BYTE i;
        BYTE Dst_High = ((Sector_Numb >> 9) & 0x07) | 0x38;
        UINT Dst_Low = ((Sector_Numb & 0x01FF) << 7) + offset;
        
	for(i = 0; i < n; i++){
		if(offset < 127){			
			PB_8255 = Dst_High;
			UP_DOWN = 1;
			* Data_Addr = XBYTE[Dst_Low];
			UP_DOWN = 0;
                        Data_Addr++;
                        Dst_Low++;
                        offset++;
		}else{
			PB_8255 = Dst_High;
			UP_DOWN = 1;
			* Data_Addr = XBYTE[Dst_Low];
			UP_DOWN = 0;
                        Data_Addr++;
			offset = 0;			   /*Address step over the boundary of one sector to the next sector*/
			Sector_Numb = Sector_Numb + 1;
                        Dst_High = ((Sector_Numb >> 9) & 0x07) | 0x38;
                        Dst_Low = ((Sector_Numb & 0x01FF) << 7);
		}
	}
}



/************************************************************************/
/* PROCEDURE: Flash_Delay_Byteprogram                                   */
/*                                                                      */
/* This procedure can delay 20us after byte program have done           */
/*                                                                      */
/* Input:                                                               */
/*      NONE                                                            */
/*                                                                      */
/* Output:                                                              */
/*      NONE                                                            */
/************************************************************************/

void Flash_Delay_ByteProgram(){
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
}

/************************************************************************/
/* PROCEDURE: Flash_Delay_EraseChip                                     */
/*                                                                      */
/* This procedure can delay 100ms to wait chip erase being done         */
/*                                                                      */
/* Input:                                                               */
/*      NONE                                                            */
/*                                                                      */
/* Output:                                                              */
/*      NONE                                                            */
/************************************************************************/

void Flash_Delay_EraseChip(){
	Flash_Delay_1ms(100);
}

/************************************************************************/
/* PROCEDURE: Flash_Delay_EraseSector                                   */
/*                                                                      */
/* This procedure can delay 25ms to wait sector erase being done        */
/*                                                                      */
/* Input:                                                               */
/*      NONE                                                            */
/*                                                                      */
/* Output:                                                              */
/*      NONE                                                            */
/************************************************************************/

void Flash_Delay_EraseSector(){
	Flash_Delay_1ms(25);
}

/************************************************************************/
/* PROCEDURE: Flash_Delay_1ms                                           */
/*                                                                      */
/* This procedure can delay 1ms                                         */
/*                                                                      */
/* Input:                                                               */
/*      NONE                                                            */
/*                                                                      */
/* Output:                                                              */
/*      NONE                                                            */
/************************************************************************/

void Flash_Delay_1ms(BYTE n){
	BYTE i,j;
	for(i = 0; i < n; i++){
		for(j = 0; j < 124; j++){;}
	}
}
